package com.ruicar.afs.cloud.batch.dayend.process;

import cn.hutool.core.collection.CollectionUtil;
import com.ruicar.afs.cloud.batch.dayend.handle.run.SystemJdbcConfig;
import com.ruicar.afs.cloud.batch.dayend.handle.run.VoucherBathRequest;
import com.ruicar.afs.cloud.batch.dayend.handle.run.VoucherBathSendProcessor;
import com.ruicar.afs.cloud.batch.frame.AbsBatchRunner;
import com.ruicar.afs.cloud.common.config.VoucherConstant;
import com.ruicar.afs.cloud.common.core.enums.AfsEnumUtil;
import com.ruicar.afs.cloud.common.core.exception.AfsBaseException;
import com.ruicar.afs.cloud.common.core.util.SpringContextHolder;
import com.ruicar.afs.cloud.common.modules.contract.enums.LendingDirection;
import com.ruicar.afs.cloud.common.modules.contract.enums.VoucherSendStatus;
import com.ruicar.afs.cloud.common.vo.AccountVoucherInfoVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @author infinity
 * @version 1.0
 * @date 2020/8/18 11:48
 */
@Slf4j
public class VoucherInfoSendBathRunner extends AbsBatchRunner {
    private static final ExecutorService EXECUTOR_SERVICE = new ThreadPoolExecutor(10, 10,
            0L, TimeUnit.MILLISECONDS,
            new LinkedBlockingQueue<Runnable>(1024));
    private SystemJdbcConfig systemJdbcConfig= SpringContextHolder.getBean(SystemJdbcConfig.class);
    private VoucherBathSendProcessor voucherBathSendProcessor= SpringContextHolder.getBean(VoucherBathSendProcessor.class);

    @Override
    public void process(String param) {
        logger.info("读取==={}", loadBreakPoint());
        Connection contractAcount = this.getConnection(systemJdbcConfig.getAccount());
        boolean isFinish = false;
        while (!isFinish) {
            //发送凭证信息
            log.info("发送凭证信息--开始");
            List<AccountVoucherInfoVo> list = handleVoucherAccountInfoList(VoucherSendStatus.NOT_SEND, contractAcount);
            if (CollectionUtil.isNotEmpty(list)) {
                VoucherBathRequest request = new VoucherBathRequest();
                request.setVos(list);
                list = voucherBathSendProcessor.process(request);
                //凭证发送状态处理数据
                handleStatus(list, contractAcount);
            } else {
                isFinish = true;
            }
            log.info("发送凭证信息--结束");
        }
        List<AccountVoucherInfoVo> list = handleVoucherAccountInfoList(VoucherSendStatus.SEND_FAIL, contractAcount);
        if (CollectionUtil.isNotEmpty(list)) {
            throw new AfsBaseException("凭证发送有误！");
        }
        logger.info("读取==={}", loadBreakPoint());
    }

    /**
     * 获取凭证信息
     * @param status
     * @param contractAcount
     * @return
     */
    private List<AccountVoucherInfoVo> handleVoucherAccountInfoList(VoucherSendStatus status, Connection contractAcount) {
        StringBuffer sql = new StringBuffer();
        sql.append(" select account.id ,account.voucher_no,account.contract_no,account.dealer_name,account.posting_date ,");
        sql.append(" entry.entry_no,entry.subject_code ,entry.lending_direction ,entry.debit_amt ,entry.credit_amt,");
        sql.append(" entry.explanation,account.child_business_code,account.source_system,account.case_type from account_voucher_entry entry inner join  (select ");
        sql.append(" info.id,info.voucher_no,info.contract_no,info.dealer_name, info.posting_date ,info.child_business_code");
        sql.append(" ,info.source_system,info.case_type from  account_voucher_info info where status=? order by info.id asc  limit 0, ? )  account ");
        sql.append("  on account.voucher_no =entry.voucher_no ");
        PreparedStatement ps = null;
        ResultSet rs = null;
        List<AccountVoucherInfoVo> list = new ArrayList<AccountVoucherInfoVo>();
        try {
            ps = contractAcount.prepareStatement(sql.toString());
            ps.setString(1, AfsEnumUtil.key(status));
            ps.setInt(2, VoucherConstant.batchesSize);
            rs = ps.executeQuery();
            while (rs != null && rs.next()) {
                AccountVoucherInfoVo vo = new AccountVoucherInfoVo();
                vo.setId(rs.getLong("id"));
                vo.setContractNo(rs.getString("contract_no"));
                vo.setVoucherNo(rs.getString("voucher_no"));
                vo.setDealerName(rs.getString("dealer_name"));
                vo.setPostingDate(rs.getDate("posting_date"));
                vo.setDealerName(rs.getString("dealer_name"));
                vo.setEntryNo(rs.getString("entry_no"));
                vo.setSubjectCode(rs.getString("subject_code"));
                vo.setLendingDirection((LendingDirection) AfsEnumUtil
                        .getEnum(rs.getString("lending_direction"), LendingDirection.class));
                vo.setDebitAmt(rs.getBigDecimal("debit_amt"));
                vo.setCreditAmt(rs.getBigDecimal("credit_amt"));
                vo.setExplanation(rs.getString("explanation"));
                vo.setChildBusinessCode(rs.getString("child_business_code"));
                vo.setSourceSystem(rs.getString("source_system"));
                vo.setCaseType(rs.getString("case_type"));
                list.add(vo);
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new AfsBaseException(e.getMessage());
        } finally {
            clean(ps);
            clean(rs);
        }
        return list;
    }

    //凭证发送状态处理数据
    private void handleStatus(List<AccountVoucherInfoVo> list, Connection contractAcount) {
        StringBuffer sql = new StringBuffer();
        sql.append("update account_voucher_info set status = ?,err_msg = ? where id =?");
        PreparedStatement ps = null;
        int count = 0;
        try {
            ps = contractAcount.prepareStatement(sql.toString());
            for (AccountVoucherInfoVo vo : list) {
                count++;
                ps.setString(1, AfsEnumUtil.key(vo.getStatus()));
                ps.setString(2, vo.getErrMsg());
                ps.setLong(3, vo.getId());
                ps.addBatch();
                if (count == VoucherConstant.batchesSize) {
                    ps.executeBatch();
                    contractAcount.commit();
                    count = 0;
                    contractAcount.setAutoCommit(false);
                }
            }
            if (count > 0) {
                ps.executeBatch();
                contractAcount.commit();
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new AfsBaseException(e.getMessage());
        } finally {
            clean(ps);
        }
    }


}
